﻿using System;
using Ah.Testudin.Engine.Events;
using Ah.Testudin.Engine.Events.Components;
using Ah.Testudin.Engine.UI.Elements;
using Ah.Testudin.Engine.UI.Elements.Debugging;
using Ah.Testudin.Engine.Utilities;
using Microsoft.Xna.Framework;

namespace Ah.Testudin.Engine.Actors.Components.Animation
{
    public class RotationAnimationComponent  : ActorComponentBase, IAnimationComponent
    {
        #region Private Member Variables

        private float _slerpAmount;

        private Vector3 _targetVector;

        private float _slerpDenominator;

        #endregion

        #region Constructors

        public RotationAnimationComponent(
            Actor owner,
            Vector3 targetVector,
            IEventManager eventManager,
            float slerpDenominator)
            : base(owner, eventManager)
        {
            _targetVector = targetVector;

            _slerpDenominator = slerpDenominator;

            _targetVector.Normalize();

            _eventManager.TriggerEvent(
                new AnimationComponentCreatedEvent(
                    this));

            _slerpAmount = 0f;

            this.Status = AnimationStatus.Running;
        }

        #endregion

        #region IActorComponent

        public override void Update(GameTime gameTime)
        {
            if (this.Status == AnimationStatus.Running)
            {
                TransformComponent transformComponent = this.Owner.GetComponent<TransformComponent>();

                Vector3 position = transformComponent.Transform.Translation;

                Vector3 forwardVector = Vector3.Normalize(transformComponent.Transform.Forward);

                float dot = (float)Math.Round(
                    Vector3.Dot(
                        forwardVector,
                        _targetVector),
                    4);

                if (dot == 1)
                {
                    this.Status = AnimationStatus.Finished;

                    return;
                }

                if (dot >= .999)
                {
                    _slerpAmount = 1.0f;
                }
                else
                {
                    _slerpAmount += (float)gameTime.ElapsedGameTime.Milliseconds / _slerpDenominator;
                }

                Vector3 rotationAxis = 
                    Vector3.Normalize(
                        Vector3.Cross(
                            _targetVector,
                            forwardVector));

                float rotationAngle = MathUtilities.GetSignedAngle(
                    forwardVector,
                    _targetVector);

                Quaternion qStart = Quaternion.CreateFromRotationMatrix(transformComponent.Transform);

                Quaternion qChange = Quaternion.CreateFromAxisAngle(rotationAxis, rotationAngle);

                Quaternion qEnd = Quaternion.Concatenate(qStart, qChange);

                Quaternion qSlerp = Quaternion.Slerp(
                    qStart,
                    qEnd,
                    _slerpAmount);

                Matrix rotation = Matrix.CreateFromQuaternion(qSlerp);

                rotation.Translation = position;

                PhysicsComponent physicsComponent = this.Owner.GetComponent<PhysicsComponent>();

                physicsComponent.KinematicMove(rotation);
            }
        }

        #endregion

        #region IAnimationComponent

        public AnimationStatus Status { get; set; }

        #endregion
    }
}
